module klang.编译.编译.扫描.扫描_;
import 全局;
import std.conv: ·to = to;
import std.typecons: ·Tuple = Tuple, ·tuple = tuple;
import klang.编译.类型.枚举值.枚举值_: TK, SK, 字符_, 令牌标志_;
import 编译数字 = 编译数字.编译;
import klang.编译.核心.核心_: 整数_, 是空白或换行, 是换行类的, 是空白单行字符, 简单链表_, 是十六进制字符, 是十进制字符, 是八进制字符;
import klang.编译.诊断集.诊断集_: 诊断集_;
import klang.编译.诊断.诊断_: 诊断消息_;
import klang.编译.类型.类型_: 设置扫描_;
import klang.编译.扫描工具.扫描工具_: 设置扫描工具环境, 获取扫描工具当前目标, 恢复原扫描工具环境;
alias 错误回调_ = void delegate(诊断消息_, long);
dstring[] 文本引号组;
dchar[][] 文本内部关注字符;
bool[] 引号内文本是否可换行设置组;
int 当前文本引号;
dstring 单行注释头;
dstring 多行注释头;
dstring 多行注释尾;
dstring[][dchar] 组合令牌设置;
dchar[] 单行注释内特殊关注字符;
dchar[] 多行注释内特殊关注字符;
//#范围 扫描器_
klang.编译.编译.扫描.扫描_.错误回调_ onError = ··null!(klang.编译.编译.扫描.扫描_.错误回调_);
bool skipTrivia = false;
dstring text = ""d;
// Current position (end position of text of current token)
long 开始;
// end of text
long end;
// Start position of whitespace 输出之前转换函数组 current token
long 起点开始;
// Start position of text of current token
long 令牌开始;
SK 令牌 = SK.未知__;
dstring tokenValue = ""d;
令牌标志_ tokenFlags = 令牌标志_.None;
bool 出现了关注字符 = false;
bool 多行注释内出现关注字符 = false;
bool 单行注释内出现关注字符 = false;
TK 保存扫描工具目标;
TK 新平台目标;
bool delegate(const(dchar)) 是标识符开始;
bool delegate(const(dchar)) 是标识符片段;
static this() {
    开始 = -1;
    end = -1;
    起点开始 = -1;
    令牌开始 = -1;
}
struct 类型和值_ {
    SK type;
    dstring value;
    this(SK t, dstring v) {
        this.type = t;
        this.value = v;
    }
}
bool 令牌是标识符或关键字(SK 令牌) {
    return 令牌 >= SK.标识符;
}
/* @internal */
bool 是标识符文本(dstring 名称) {
    dchar ch = (cast()(名称[0]));
    if (!.是标识符开始(ch)) {
        return false;
    }
    {
        for (int i = 0; i < 名称.length; ++i) {
            ch = (cast()(名称[i]));
            if (!.是标识符片段(ch)) {
                return false;
            }
        }
    }
    return true;
}
void 设置扫描器(设置扫描_ 设置) {
    .文本引号组 = 设置.文本引号组();
    .文本内部关注字符 = 设置.文本内部关注字符();
    .引号内文本是否可换行设置组 = 设置.引号内文本是否可换行设置组();
    .单行注释头 = 设置.单行注释头();
    .单行注释内特殊关注字符 = 设置.单行注释内特殊关注字符();
    .多行注释头 = 设置.多行注释头();
    .多行注释尾 = 设置.多行注释尾();
    .多行注释内特殊关注字符 = 设置.多行注释内特殊关注字符();
    .组合令牌设置 = .生成字符表(设置.组合令牌设置());
    .保存扫描工具目标 = 获取扫描工具当前目标();
    .新平台目标 = 设置.获取语言目标();
    设置扫描工具环境(.新平台目标, .单行注释头, .多行注释头, .多行注释尾);
    .是标识符开始 = 设置.获取标识符开始判断函数();
    .是标识符片段 = 设置.获取标识符片段片段函数();
}
dstring[][dchar] 生成字符表(dstring[] 数组) {
    dstring[][dchar] ret;
    foreach (dstring s; 数组) {
        if (s !is ··null!(dstring)) {
            dchar ch = (cast()(s[0]));
            if (.具有!(dstring[], dchar)(ret, ch) is ··null!(dstring[]*)) {
                ret[ch] = [s];
            }
            else {
                .追加!(dstring)(ret[ch], s);
            }
        }
    }
    return ret;
}
void 恢复扫描工具() {
    恢复原扫描工具环境(.保存扫描工具目标, .新平台目标);
}
bool 是出现了关注字符() {
    return .出现了关注字符;
}
bool 单行注释内出现了关注字符() {
    return .单行注释内出现关注字符;
}
bool 多行注释内出现了关注字符() {
    return .单行注释内出现关注字符;
}
long getStartPos() {
    return .起点开始;
}
SK getToken() {
    return .令牌;
}
long getTextPos() {
    return .开始;
}
long getTokenPos() {
    return .令牌开始;
}
dstring getTokenText() {
    return text[.令牌开始 .. .开始];
}
dstring getTokenValue() {
    return .tokenValue;
}
bool hasUnicodeEscape() {
    return (.tokenFlags & 令牌标志_.UnicodeEscape) != 0;
}
bool hasExtendedUnicodeEscape() {
    return (.tokenFlags & 令牌标志_.ExtendedUnicodeEscape) != 0;
}
bool 前面有换行符() {
    return (.tokenFlags & 令牌标志_.PrecedingLineBreak) != 0;
}
bool isUnterminated() {
    return (.tokenFlags & 令牌标志_.Unterminated) != 0;
}
令牌标志_ getTokenFlags() {
    return .tokenFlags;
}
void error0(诊断消息_ message) {
    .error2(message);
}
void error2(诊断消息_ message, long errPos = 0, long 长度 = 0) {
    if (errPos == 0) {
        errPos = .开始;
    }
    if (.onError !is ··null!(错误回调_)) {
        long oldPos = .开始;
        .开始 = errPos;
        .onError(message, 长度);
        .开始 = oldPos;
    }
}
dstring scanNumberFragment() {
    long start = .开始;
    bool allowSeparator = false;
    bool isPreviousTokenSeparator = false;
    dstring result = ""d;
    while(true) {
        immutable(dchar) ch = text[开始];
        if (ch == 字符_.下划线) {
            .tokenFlags |= 令牌标志_.ContainsSeparator;
            if (allowSeparator) {
                allowSeparator = false;
                isPreviousTokenSeparator = true;
                result ~= text[start .. .开始];
            }
            else if (isPreviousTokenSeparator) {
                .error2(诊断集_.Multiple_consecutive_numeric_separators_are_not_permitted, .开始, 1);
            }
            else {
                .error2(诊断集_.Numeric_separators_are_not_allowed_here, .开始, 1);
            }
            ++开始;
            start = .开始;
            continue;
        }
        if (是十进制字符(ch)) {
            allowSeparator = true;
            isPreviousTokenSeparator = false;
            ++开始;
            continue;
        }
        break;
    }
    if (text[.开始 - 1] == 字符_.下划线) {
        .error2(诊断集_.Numeric_separators_are_not_allowed_here, .开始 - 1, 1);
    }
    return result ~ text[start .. .开始];
}
dstring scanOctalDigits() {
    long start = .开始;
    while(是八进制字符(text[开始])) {
        ++开始;
    }
    return text[start .. .开始];
}
/**
 * Scans the given 整数_ of hexadecimal digits in the text,
 * returning -1 如果 the given 整数_ is unavailable.
 */
auto scanExactNumberOfHexDigits(int count, bool canHaveSeparators, bool 保持原始文本 = false) {
    dstring valueString = .scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ false, canHaveSeparators);
    if (保持原始文本) {
        return ·tuple(valueString, 0);
    }
    if (valueString !is ··null!(dstring)) {
        return ·tuple(""d, 编译数字.编译!(int)(valueString, 16));
    }
    return ·tuple(""d, 0);
}
/**
 * Scans as many hexadecimal digits as are available in the text,
 * returning "" 如果 the given 整数_ of digits was unavailable.
 */
dstring scanMinimumNumberOfHexDigits(long count, bool canHaveSeparators) {
    return .scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ true, canHaveSeparators);
}
dstring scanHexDigits(long minCount, bool scanAsManyAsPossible, bool canHaveSeparators) {
    dstring valueChars = ""d;
    bool allowSeparator = false;
    bool isPreviousTokenSeparator = false;
    while(valueChars.length < minCount || scanAsManyAsPossible) {
        dchar ch = (cast()(text[开始]));
        if (canHaveSeparators && ch == 字符_.下划线) {
            .tokenFlags |= 令牌标志_.ContainsSeparator;
            if (allowSeparator) {
                allowSeparator = false;
                isPreviousTokenSeparator = true;
            }
            else if (isPreviousTokenSeparator) {
                .error2(诊断集_.Multiple_consecutive_numeric_separators_are_not_permitted, .开始, 1);
            }
            else {
                .error2(诊断集_.Numeric_separators_are_not_allowed_here, .开始, 1);
            }
            ++开始;
            continue;
        }
        allowSeparator = canHaveSeparators;
        if (ch >= 字符_.A && ch <= 字符_.F) {
            ch += 字符_.a - 字符_.A; // standardize hex literals to lowercase
        }
        else if (!((ch >= 字符_.数_0 && ch <= 字符_.数_9) || (ch >= 字符_.a && ch <= 字符_.f))) {
            break;
        }
        valueChars ~= ·to!(dstring)([ch]);
        ++开始;
        isPreviousTokenSeparator = false;
    }
    if (valueChars.length < minCount) {
        valueChars = ""d;
    }
    if (text[.开始 - 1] == 字符_.下划线) {
        .error2(诊断集_.Numeric_separators_are_not_allowed_here, .开始 - 1, 1);
    }
    return valueChars;
}
dstring scanEscapeSequence(bool 保持原始文本 = false) {
    ++开始;
    if (.开始 >= .end) {
        .error0(诊断集_.Unexpected_end_of_text);
        return ""d;
    }
    immutable(dchar) ch = text[开始];
    ++开始;
    switch (ch) {
        case 字符_.数_0: {
            if (.开始 + 1 < .end) {
                immutable(dchar) ch2 = text[开始];
                if (是十六进制字符(ch2)) {
                    .tokenFlags |= 令牌标志_.未解码转义;
                    dstring 内容 = ·to!(dstring)([字符_.反斜杠, ch, text[开始]]);
                    ++开始;
                    return 内容;
                }
            }
            return "\0"d;
        }
        case 字符_.b: {
            return "\b"d;
        }
        case 字符_.t: {
            return "\t"d;
        }
        case 字符_.n: {
            return "\n"d;
        }
        case 字符_.v: {
            return "\v"d;
        }
        case 字符_.f: {
            if (.开始 + 1 < .end) {
                immutable(dchar) ch2 = text[开始];
                if (是十六进制字符(ch2)) {
                    .tokenFlags |= 令牌标志_.未解码转义;
                    dstring 内容 = ·to!(dstring)([字符_.反斜杠, ch, text[开始]]);
                    ++开始;
                    return 内容;
                }
            }
            return "\f"d;
        }
        case 字符_.r: {
            return "\r"d;
        }
        case 字符_.单引: {
            return "'"d;
        }
        case 字符_.双引: {
            return "\""d;
        }
        case 字符_.U: {
            .tokenFlags |= 令牌标志_.ExtendedUnicodeEscape;
            return .scanExtendedUnicodeEscape(保持原始文本);
        }
        case 字符_.u: {
            .tokenFlags |= 令牌标志_.UnicodeEscape;
            // '\uDDDD'
            return .scanHexadecimalEscape(/*numDigits*/ 4, 保持原始文本);
        }
        case 字符_.x: {
            // '\xDD'
            .tokenFlags |= 令牌标志_.AsciiEscape;
            return .scanHexadecimalEscape(/*numDigits*/ 2, 保持原始文本);
        }
        // when encountering a LineContinuation (i.e. a 反斜杠 and a line terminator sequence),
        // the line terminator is interpreted to be "the empty code unit sequence".
        case 字符_.回车符: {
            if (.开始 < .end && text[开始] == 字符_.换行符) {
                ++开始;
            }
        }
        // falls through
        case 字符_.换行符:
        case 字符_.行分隔符:
        case 字符_.段落分隔符: {
            return ""d;
        }
        default: {
            .tokenFlags |= 令牌标志_.未解码转义;
            dstring 内容 = ·to!(dstring)([字符_.反斜杠, ch, text[开始]]);
            ++开始;
            return 内容;
        }
    }
}
dstring scanHexadecimalEscape(int numDigits, bool 保持原始文本 = false) {
    ·Tuple!(dstring, int) escapedValue = .scanExactNumberOfHexDigits(numDigits, /*canHaveSeparators*/ false, 保持原始文本);
    if (escapedValue[0] !is ··null!(dstring)) {
        return escapedValue[0];
    }
    if (escapedValue[1] >= 0) {
        return numDigits == 2 ? ·to!(dstring)(·to!(string)([(cast(char)(escapedValue[1]))])) : ·to!(dstring)(·to!(wstring)([(cast(wchar)(escapedValue[1]))]));
    }
    else {
        .error0(诊断集_.Hexadecimal_digit_expected);
        return ""d;
    }
}
dstring scanExtendedUnicodeEscape(bool 保持原始文本 = false) {
    dstring escapedValueString = .scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false);
    if (保持原始文本) {
        return escapedValueString;
    }
    int escapedValue = escapedValueString ? 编译数字.编译!(int)(escapedValueString, 16) : -1;
    bool isInvalidExtendedEscape = false;
    // Validate the value of the digit
    if (escapedValue < 0) {
        .error0(诊断集_.Hexadecimal_digit_expected);
        isInvalidExtendedEscape = true;
    }
    else if (escapedValue > 1114111) {
        .error0(诊断集_.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive);
        isInvalidExtendedEscape = true;
    }
    if (.开始 >= .end) {
        .error0(诊断集_.Unexpected_end_of_text);
        isInvalidExtendedEscape = true;
    }
    if (isInvalidExtendedEscape) {
        return ""d;
    }
    return ·to!(dstring)([(cast(dchar)(escapedValue))]);
}
// Current character is known to be a 反斜杠. Check for Unicode escape of the form '\uXXXX'
// and 返回 code point value 如果 valid Unicode escape is found. Otherwise 返回 -1.
int peekUnicodeEscape() {
    if (.开始 + 5 < .end && text[.开始 + 1] == 字符_.u) {
        long start = .开始;
        .开始 += 2;
        ·Tuple!(dstring, int) value = .scanExactNumberOfHexDigits(4, /*canHaveSeparators*/ false, /*保持原始文本*/ false);
        .开始 = start;
        return value[1];
    }
    return -1;
}
int peekExtendedUnicodeEscape() {
    if (text[.开始 + 1] == 字符_.U) {
        long start = .开始;
        .开始 += 2;
        dstring escapedValueString = .scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false);
        int escapedValue = escapedValueString ? 编译数字.编译!(int)(escapedValueString, 16) : -1;
        .开始 = start;
        return escapedValue;
    }
    return -1;
}
SK 扫描标识符() {
    .开始 += 1;
    dchar ch = (cast()(text[开始]));
    while(.开始 < .end && .是标识符片段(ch)) {
        .开始 += 1;
        ch = (cast()(text[开始]));
    }
    .tokenValue = text[.令牌开始 .. .开始];
    if (ch == 字符_.反斜杠) {
        .tokenValue ~= .扫描标识符片段();
    }
    return .令牌 = SK.标识符;
}
dstring 扫描标识符片段() {
    dstring result = ""d;
    long start = .开始;
    while(.开始 < .end) {
        dchar ch = (cast()(text[开始]));
        if (.是标识符片段(ch)) {
            .开始 += 1;
        }
        else if (ch == 字符_.反斜杠) {
            ch = .peekExtendedUnicodeEscape();
            if (ch >= 0 && .是标识符片段(ch)) {
                .开始 += 3;
                .tokenFlags |= 令牌标志_.ExtendedUnicodeEscape;
                result ~= .scanExtendedUnicodeEscape();
                start = .开始;
                continue;
            }
            ch = .peekUnicodeEscape();
            if (!(ch >= 0 && .是标识符片段(ch))) {
                break;
            }
            .tokenFlags |= 令牌标志_.UnicodeEscape;
            result ~= text[start .. .开始];
            result ~= ·to!(dstring)([ch]);
            // Valid Unicode escape is always six characters
            .开始 += 6;
            start = .开始;
        }
        else {
            break;
        }
    }
    result ~= text[start .. .开始];
    return result;
}
dstring scanBinaryOrOctalDigits(int base) {
    dstring value = ""d;
    // For counting 整数_ of digits; Valid binaryIntegerLiteral must have 艾特 least one binary digit following B or b.
    // Similarly valid octalIntegerLiteral must have 艾特 least one octal digit following o or O.
    bool separatorAllowed = false;
    bool isPreviousTokenSeparator = false;
    while(true) {
        immutable(dchar) ch = text[开始];
        // Numeric separators are allowed anywhere within a numeric literal, except not 艾特 the beginning, or following another separator
        if (ch == 字符_.下划线) {
            .tokenFlags |= 令牌标志_.ContainsSeparator;
            if (separatorAllowed) {
                separatorAllowed = false;
                isPreviousTokenSeparator = true;
            }
            else if (isPreviousTokenSeparator) {
                .error2(诊断集_.Multiple_consecutive_numeric_separators_are_not_permitted, .开始, 1);
            }
            else {
                .error2(诊断集_.Numeric_separators_are_not_allowed_here, .开始, 1);
            }
            ++开始;
            continue;
        }
        separatorAllowed = true;
        if (!是十进制字符(ch) || ch - 字符_.数_0 >= base) {
            break;
        }
        value ~= ·to!(dstring)([text[开始]]);
        ++开始;
        isPreviousTokenSeparator = false;
    }
    if (text[.开始 - 1] == 字符_.下划线) {
        // Literal ends with underscore - not allowed
        .error2(诊断集_.Numeric_separators_are_not_allowed_here, .开始 - 1, 1);
    }
    return value;
}
T speculationHelper(T)(T delegate() 回调, bool isLookahead) {
    long savePos = .开始;
    long saveStartPos = .起点开始;
    long saveTokenPos = .令牌开始;
    SK saveToken = .令牌;
    dstring saveTokenValue = .tokenValue;
    令牌标志_ saveTokenFlags = .tokenFlags;
    bool 储存出现了关注字符 = .出现了关注字符;
    bool 储存多行注释内出现关注字符 = .多行注释内出现关注字符;
    bool 储存单行注释内出现关注字符 = .单行注释内出现关注字符;
    T result = 回调();
    // If our 回调 returned something 'falsy' or we're just looking ahead,
    // then unconditionally restore us to where we were.
    if ((result is ··null!(T)) || isLookahead) {
        .开始 = savePos;
        .起点开始 = saveStartPos;
        .令牌开始 = saveTokenPos;
        .令牌 = saveToken;
        .tokenValue = saveTokenValue;
        .tokenFlags = saveTokenFlags;
        .出现了关注字符 = 储存出现了关注字符;
        .多行注释内出现关注字符 = 储存多行注释内出现关注字符;
        .单行注释内出现关注字符 = 储存单行注释内出现关注字符;
    }
    return result;
}
T scanRange(T)(long start, long 长度, T delegate() 回调) {
    long saveEnd = .end;
    long savePos = .开始;
    long saveStartPos = .起点开始;
    long saveTokenPos = .令牌开始;
    SK saveToken = .令牌;
    dstring saveTokenValue = .tokenValue;
    令牌标志_ saveTokenFlags = .tokenFlags;
    bool 储存出现了关注字符 = .出现了关注字符;
    .setText(.text, start, 长度);
    T result = 回调();
    .end = saveEnd;
    .开始 = savePos;
    .起点开始 = saveStartPos;
    .令牌开始 = saveTokenPos;
    .令牌 = saveToken;
    .tokenValue = saveTokenValue;
    .tokenFlags = saveTokenFlags;
    .出现了关注字符 = 储存出现了关注字符;
    return result;
}
T lookAhead(T)(T delegate() 回调) {
    return .speculationHelper!(T)(cast(T delegate())(回调), /*isLookahead*/ true);
}
T tryScan(T)(T delegate() 回调) {
    return .speculationHelper!(T)(cast(T delegate())(回调), /*isLookahead*/ false);
}
dstring getText() {
    return .text;
}
void setText(dstring newText, long start, long 长度) {
    .text = newText;
    if (start + 长度 == 0) {
        .end = text.length;
    }
    else {
        .end = start + 长度;
    }
    .setTextPos(start);
}
void setOnError(错误回调_ errorCallback) {
    .onError = cast(错误回调_)(errorCallback);
}
void setTextPos(long textPos) {
    assert(textPos >= 0, "textPos 错误"c);
    .开始 = textPos;
    .起点开始 = textPos;
    .令牌开始 = textPos;
    .令牌 = SK.未知__;
    .tokenValue = ""d;
    .tokenFlags = 令牌标志_.None;
}
dstring 获取当前字面量引号() {
    return 文本引号组[当前文本引号];
}
bool 是文本字面量引号(dchar ch, dstring 内容) {
    {
        循环1: for (int i = 0; i < 文本引号组.length; ++i) {
            dstring 文本引号 = 文本引号组[i];
            if (文本引号.length == 1) {
                bool ret = ch == 文本引号[0];
                if (ret) {
                    .当前文本引号 = i;
                    return ret;
                }
                continue 循环1;
            }
            else if (文本引号.length == 2) {
                bool ret = ch == 文本引号[0] && .开始 + 1 < .end && 内容[.开始 + 1] == 文本引号[1];
                if (ret) {
                    .当前文本引号 = i;
                    return ret;
                }
                continue 循环1;
            }
            else if (文本引号.length == 3) {
                bool ret = ch == 文本引号[0] && .开始 + 2 < .end && 内容[.开始 + 1] == 文本引号[1] && 内容[.开始 + 2] == 文本引号[2];
                if (ret) {
                    .当前文本引号 = i;
                    return ret;
                }
                continue 循环1;
            }
            else {
                long 索引 = .开始 + 1;
                {
                    for (int ii = 0; ii < 文本引号.length; ++ii, ++索引) {
                        immutable(dchar) v = 文本引号[ii];
                        if (ch != v) {
                            continue 循环1;
                        }
                        if (索引 < 内容.length) {
                            ch = (cast()(内容[索引]));
                        }
                        else {
                            continue 循环1;
                        }
                    }
                }
                .当前文本引号 = i;
                return true;
            }
        }
    }
    return false;
}
bool 是当前文本引号(dchar ch, dstring 内容) {
    dstring 文本引号 = 文本引号组[当前文本引号];
    if (文本引号.length == 1) {
        bool ret = ch == 文本引号[0];
        return ret;
    }
    if (文本引号.length == 2) {
        bool ret = ch == 文本引号[0] && .开始 + 1 < .end && 内容[.开始 + 1] == 文本引号[1];
        return ret;
    }
    long 索引 = .开始 + 1;
    {
        for (int ii = 0; ii < 文本引号.length; ++ii, ++索引) {
            immutable(dchar) v = 文本引号[ii];
            if (ch != v) {
                return false;
            }
            if (索引 < 内容.length) {
                ch = (cast()(内容[索引]));
            }
            else {
                return false;
            }
        }
    }
    return true;
}
bool 是单行注释开始(dchar ch, dstring 内容) {
    if (单行注释头.length == 1) {
        return ch == 单行注释头[0];
    }
    if (单行注释头.length == 2) {
        return ch == 单行注释头[0] && .开始 + 1 < .end && 内容[.开始 + 1] == 单行注释头[1];
    }
    long 索引 = .开始 + 1;
    {
        for (int i = 0; i < 单行注释头.length; ++i, ++索引) {
            immutable(dchar) v = 单行注释头[i];
            if (ch != v) {
                return false;
            }
            if (索引 < 内容.length) {
                ch = (cast()(内容[索引]));
            }
            else {
                return false;
            }
        }
    }
    return true;
}
bool 是多行注释开始(dchar ch, dstring 内容) {
    if (多行注释头.length == 1) {
        return ch == 多行注释头[0];
    }
    if (多行注释头.length == 2) {
        return ch == 多行注释头[0] && .开始 + 1 < .end && 内容[.开始 + 1] == 多行注释头[1];
    }
    long 索引 = .开始 + 1;
    {
        for (int i = 0; i < 多行注释头.length; ++i, ++索引) {
            immutable(dchar) v = 多行注释头[i];
            if (ch != v) {
                return false;
            }
            if (索引 < 内容.length) {
                ch = (cast()(内容[索引]));
            }
            else {
                return false;
            }
        }
    }
    return true;
}
bool 是多行注释结尾(dchar ch, dstring 内容) {
    if (多行注释尾.length == 1) {
        return ch == 多行注释尾[0];
    }
    if (多行注释尾.length == 2) {
        return ch == 多行注释尾[0] && .开始 + 1 < .end && 内容[.开始 + 1] == 多行注释尾[1];
    }
    long 索引 = .开始 + 1;
    {
        for (int i = 0; i < 多行注释尾.length; ++i, ++索引) {
            immutable(dchar) v = 多行注释尾[i];
            if (ch != v) {
                return false;
            }
            if (索引 < 内容.length) {
                ch = (cast()(内容[索引]));
            }
            else {
                return false;
            }
        }
    }
    return true;
}
void 创建扫描(bool _skipTrivia, dstring _textInitial = ··null!(dstring), 错误回调_ _onError = ··null!(错误回调_), long _start = 0, long _length = 0) {
    .skipTrivia = _skipTrivia;
    if (_textInitial !is ··null!(dstring)) {
        .text = _textInitial;
    }
    if (_onError !is ··null!(错误回调_)) {
        .onError = cast(错误回调_)(_onError);
    }
    if (_start != 0) {
        .开始 = _start;
    }
    if (_length != 0) {
        .end = _length;
    }
    else {
        .end = text.length;
    }
}
bool 扫描连续标点() {
    dchar ch = (cast()(text[开始]));
    if (.具有!(dstring[], dchar)(.组合令牌设置, ch) !is ··null!(dstring[]*)) {
        dstring[] ss = 组合令牌设置[ch];
        {
            for (int i = 0; i < ss.length; ++i) {
                dstring s = ss[i];
                if (s == text[.开始 .. .开始 + s.length]) {
                    .开始 += s.length;
                    return true;
                }
            }
        }
    }
    return false;
}
bool 预扫描(dstring sks) {
    dstring s = text[.开始 - 1 .. .开始 + sks.length - 1];
    if (s == sks) {
        .开始 += sks.length;
        return true;
    }
    return false;
}
SK 扫描() {
    .起点开始 = .开始;
    .tokenFlags = 令牌标志_.None;
    .出现了关注字符 = false;
    .多行注释内出现关注字符 = false;
    .单行注释内出现关注字符 = false;
    while(true) {
        .令牌开始 = .开始;
        if (.开始 >= .end) {
            return .令牌 = SK.文件结尾;
        }
        dchar ch = (cast()(text[开始]));
        if (.是文本字面量引号(ch, .text)) {
            bool 可换行 = 引号内文本是否可换行设置组[当前文本引号];
            .tokenValue = 可换行 ? .扫描可换行文本() : .扫描文本();
            return .令牌 = SK.文本字面量;
        }
        else if (.是多行注释开始(ch, .text)) {
            .开始 += 多行注释头.length;
            .tokenFlags |= 令牌标志_.令牌前有杂项;
            .tokenFlags |= 令牌标志_.PrecedingJSDocComment;
            bool commentClosed = false;
            while(.开始 < .end) {
                dchar ch2 = (cast()(text[开始]));
                if (!.多行注释内出现关注字符 && 多行注释内特殊关注字符.length > 0) {
                    foreach (dchar ch4; .多行注释内特殊关注字符) {
                        if (ch4 == ch2) {
                            .多行注释内出现关注字符 = true;
                            break;
                        }
                    }
                }
                if (.是多行注释结尾(ch2, .text)) {
                    .开始 += 多行注释尾.length;
                    commentClosed = true;
                    break;
                }
                if (是换行类的(ch2)) {
                    .tokenFlags |= 令牌标志_.PrecedingLineBreak;
                }
                ++开始;
            }
            if (!commentClosed) {
                .error0(诊断集_.Asterisk_Slash_expected);
            }
            if (.skipTrivia) {
                continue;
            }
            else {
                if (!commentClosed) {
                    .tokenFlags |= 令牌标志_.Unterminated;
                }
                .tokenValue = text[.令牌开始 .. .开始];
                return .令牌 = SK.多行注释;
            }
        }
        else if (.是单行注释开始(ch, .text)) {
            .tokenFlags |= 令牌标志_.令牌前有杂项;
            .开始 += 单行注释头.length;
            while(.开始 < .end) {
                immutable(dchar) ch5 = text[开始];
                if (!.单行注释内出现关注字符 && 单行注释内特殊关注字符.length > 0) {
                    foreach (dchar ch6; .多行注释内特殊关注字符) {
                        if (ch5 == ch5) {
                            .单行注释内出现关注字符 = true;
                            break;
                        }
                    }
                }
                if (是换行类的(ch5)) {
                    break;
                }
                ++开始;
            }
            if (.skipTrivia) {
                continue;
            }
            else {
                .tokenValue = text[.令牌开始 .. .开始];
                return .令牌 = SK.单行注释;
            }
        }
        switch (ch) {
            case 字符_.换行符:
            case 字符_.回车符: {
                .tokenFlags |= 令牌标志_.令牌前有杂项;
                .tokenFlags |= 令牌标志_.PrecedingLineBreak;
                if (.skipTrivia) {
                    ++开始;
                    continue;
                }
                else {
                    if (ch == 字符_.回车符 && .开始 + 1 < .end && text[.开始 + 1] == 字符_.换行符) {
                        // consume both CR and LF
                        .开始 += 2;
                    }
                    else {
                        ++开始;
                    }
                    .tokenValue = text[.令牌开始 .. .开始];
                    return .令牌 = SK.新行;
                }
            }
            case 字符_.水平制表:
            case 字符_.垂直制表:
            case 字符_.分页:
            case 字符_.空格:
            case 字符_.不间断空格:
            case 字符_.欧甘符:
            case 字符_.半角四空:
            case 字符_.全角四空:
            case 字符_.半角空格:
            case 字符_.全角空格:
            case 字符_.三分之一全角空格:
            case 字符_.四分之一全角空格:
            case 字符_.六分之一全角空格:
            case 字符_.数字空格:
            case 字符_.标点空格:
            case 字符_.超薄空格:
            case 字符_.超细空格:
            case 字符_.零宽度空格:
            case 字符_.窄无换行空格:
            case 字符_.表意空格:
            case 字符_.数学模型空格:
            case 字符_.字节顺序标记: {
                .tokenFlags |= 令牌标志_.令牌前有杂项;
                if (.skipTrivia) {
                    ++开始;
                    continue;
                }
                else {
                    while(.开始 < .end && 是空白单行字符(text[开始])) {
                        ++开始;
                    }
                    .tokenValue = text[.令牌开始 .. .开始];
                    return .令牌 = SK.空白;
                }
            }
            case 字符_.叹号: {
                return ._扫描标点侧重标点(SK.叹号);
            }
            case 字符_.双引: {
                return ._扫描标点侧重标点(SK.双引号);
            }
            case 字符_.单引: {
                return ._扫描标点侧重标点(SK.单引号);
            }
            case 字符_.反引: {
                return ._扫描标点侧重标点(SK.反引号);
            }
            case 字符_.百分: {
                return ._扫描标点侧重标点(SK.百分号);
            }
            case 字符_.且号: {
                return ._扫描标点侧重标点(SK.且号);
            }
            case 字符_.左括号: {
                return ._扫描标点侧重标点(SK.左括号);
            }
            case 字符_.右括号: {
                return ._扫描标点侧重标点(SK.右括号);
            }
            case 字符_.星号: {
                return ._扫描标点侧重标点(SK.星号);
            }
            case 字符_.加号: {
                return ._扫描标点侧重标点(SK.加号);
            }
            case 字符_.逗号: {
                return ._扫描标点侧重标点(SK.逗号);
            }
            case 字符_.减号: {
                return ._扫描标点侧重标点(SK.减号);
            }
            case 字符_.斜杠: {
                return ._扫描标点侧重标点(SK.除号);
            }
            case 字符_.点号: {
                if (.开始 + 1 < .end && 是十进制字符(text[.开始 + 1])) {
                    .tokenValue = .扫描数字().value;
                    return .令牌 = SK.数字字面量;
                }
                return ._扫描标点侧重标点(SK.点号);
            }
            case 字符_.数_0:
            case 字符_.数_1:
            case 字符_.数_2:
            case 字符_.数_3:
            case 字符_.数_4:
            case 字符_.数_5:
            case 字符_.数_6:
            case 字符_.数_7:
            case 字符_.数_8:
            case 字符_.数_9: {
                类型和值_ 类型和值 = .扫描数字();
                .令牌 = 类型和值.type;
                .tokenValue = 类型和值.value;
                return .令牌;
            }
            case 字符_.冒号: {
                return ._扫描标点侧重标点(SK.冒号);
            }
            case 字符_.分号: {
                return ._扫描标点侧重标点(SK.分号);
            }
            case 字符_.左尖括号: {
                return ._扫描标点侧重标点(SK.左尖括号);
            }
            case 字符_.等号: {
                return ._扫描标点侧重标点(SK.等号);
            }
            case 字符_.右尖括号: {
                return ._扫描标点侧重标点(SK.右尖括号);
            }
            case 字符_.问号: {
                return ._扫描标点侧重标点(SK.问号);
            }
            case 字符_.左方括号: {
                return ._扫描标点侧重标点(SK.左方括号);
            }
            case 字符_.右方括号: {
                return ._扫描标点侧重标点(SK.右方括号);
            }
            case 字符_.异或号: {
                return ._扫描标点侧重标点(SK.异或号);
            }
            case 字符_.左大括号: {
                return ._扫描标点侧重标点(SK.左大括号);
            }
            case 字符_.或号: {
                return ._扫描标点侧重标点(SK.或号);
            }
            case 字符_.右大括号: {
                return ._扫描标点侧重标点(SK.右大括号);
            }
            case 字符_.波折: {
                return ._扫描标点侧重标点(SK.波折号);
            }
            case 字符_.艾特: {
                return ._扫描标点侧重标点(SK.艾特);
            }
            case 字符_.美元: {
                return ._扫描标点侧重标识符(SK.美元);
            }
            case 字符_.反斜杠: {
                return ._扫描标点侧重标识符(SK.反斜杠);
            }
            case 字符_.井号: {
                return ._扫描标点侧重标识符(SK.井号);
            }
            case 字符_.下划线: {
                return ._扫描标点侧重标识符(SK.下划线);
            }
            default: {
                if (.是标识符开始(ch)) {
                    return .扫描标识符();
                }
                else if (是空白单行字符(ch)) {
                    .开始 += 1;
                    continue;
                }
                else if (是换行类的(ch)) {
                    .tokenFlags |= 令牌标志_.PrecedingLineBreak;
                    .开始 += 1;
                    continue;
                }
                .error0(诊断集_.Invalid_character);
                .开始 += 1;
                .tokenValue = text[.令牌开始 .. .开始];
                return .令牌 = SK.未知__;
            }
        }
    }
}
SK _扫描标点侧重标识符(SK sk) {
    if (.扫描连续标点()) {
        .tokenValue = text[.令牌开始 .. .开始];
        return .令牌 = SK.连续运算符;
    }
    else if (.是标识符开始((cast()(text[开始])))) {
        return .扫描标识符();
    }
    ++开始;
    return .令牌 = sk;
}
SK _扫描标点侧重标点(SK sk) {
    if (.是标识符开始((cast()(text[开始])))) {
        return .扫描标识符();
    }
    else if (.扫描连续标点()) {
        .tokenValue = text[.令牌开始 .. .开始];
        return .令牌 = SK.连续运算符;
    }
    ++开始;
    .tokenValue = text[.令牌开始 .. .开始];
    return .令牌 = sk;
}
类型和值_ 扫描数字() {
    long start = .开始;
    dstring mainFragment = .scanNumberFragment();
    dstring decimalFragment;
    dstring scientificFragment;
    if (text[开始] == 字符_.点号 && text[.开始 + 1] != 字符_.点号) {
        ++开始;
        .tokenFlags |= 令牌标志_.是小数_;
        decimalFragment = .scanNumberFragment();
    }
    long end = .开始;
    if (text[开始] == 字符_.E || text[开始] == 字符_.e) {
        ++开始;
        .tokenFlags |= 令牌标志_.Scientific;
        if (text[开始] == 字符_.加号 || text[开始] == 字符_.减号) {
            ++开始;
        }
        long preNumericPart = .开始;
        dstring finalFragment = .scanNumberFragment();
        if (finalFragment is ··null!(dstring)) {
            .error0(诊断集_.Digit_expected);
        }
        else {
            scientificFragment = text[end .. preNumericPart] ~ finalFragment;
            end = .开始;
        }
    }
    dstring result;
    if ((.tokenFlags & 令牌标志_.ContainsSeparator) != 0) {
        result = mainFragment;
        if (decimalFragment !is ··null!(dstring)) {
            result ~= "."d ~ decimalFragment;
        }
        if (scientificFragment !is ··null!(dstring)) {
            result ~= scientificFragment;
        }
    }
    else {
        result = text[start .. end]; // No need to use all the fragments; no _ removal needed
    }
    .tokenValue = result;
    类型和值_ ···tempS·0·_1;
    {
        ···tempS·0·_1.type = SK.数字字面量;
        ···tempS·0·_1.value = .tokenValue;
    }
    return ···tempS·0·_1;
}
dstring 扫描文本() {
    dstring 当前引号文本 = 文本引号组[当前文本引号];
    dchar[] 关注字符组 = 文本内部关注字符[当前文本引号];
    bool 需要关注特殊字符 = 关注字符组.length > 0;
    .开始 += 当前引号文本.length;
    dstring result = ""d;
    long start = .开始;
    while(true) {
        if (.开始 >= .end) {
            result ~= text[start .. .开始];
            .tokenFlags |= 令牌标志_.Unterminated;
            .error0(诊断集_.Unterminated_string_literal);
            break;
        }
        dchar ch = (cast()(text[开始]));
        if (需要关注特殊字符 && !.出现了关注字符) {
            {
                for (int i = 0; i < 关注字符组.length; ++i) {
                    if (ch == 关注字符组[i]) {
                        .出现了关注字符 = true;
                        break;
                    }
                }
            }
        }
        if (.是当前文本引号(ch, .text)) {
            result ~= text[start .. .开始];
            .开始 += 当前引号文本.length;
            break;
        }
        if (ch == 字符_.反斜杠) {
            result ~= text[start .. .开始];
            result ~= .scanEscapeSequence();
            start = .开始;
            continue;
        }
        if (是换行类的(ch)) {
            result ~= text[start .. .开始];
            .tokenFlags |= 令牌标志_.Unterminated;
            .error0(诊断集_.Unterminated_string_literal);
            break;
        }
        ++开始;
    }
    return result;
}
dstring 扫描可换行文本() {
    dstring 当前引号文本 = 文本引号组[当前文本引号];
    dchar[] 关注字符组 = 文本内部关注字符[当前文本引号];
    bool 需要关注特殊字符 = 关注字符组.length > 0;
    .开始 += 当前引号文本.length;
    long start = .开始;
    dstring contents = ""d;
    while(true) {
        if (.开始 >= .end) {
            contents ~= text[start .. .开始];
            .tokenFlags |= 令牌标志_.Unterminated;
            .error0(诊断集_.Unterminated_template_literal);
            break;
        }
        dchar currChar = (cast()(text[开始]));
        if (需要关注特殊字符 && !.出现了关注字符) {
            {
                for (int i = 0; i < 关注字符组.length; ++i) {
                    if (currChar == 关注字符组[i]) {
                        .出现了关注字符 = true;
                        break;
                    }
                }
            }
        }
        // '`'
        if (.是当前文本引号(currChar, .text)) {
            contents ~= text[start .. .开始];
            .开始 += 当前引号文本.length;
            break;
        }
        // Escape character
        if (currChar == 字符_.反斜杠) {
            contents ~= text[start .. .开始];
            contents ~= .scanEscapeSequence();
            start = .开始;
            continue;
        }
        if (currChar == 字符_.回车符) {
            contents ~= text[start .. .开始];
            ++开始;
            if (.开始 < .end && text[开始] == 字符_.换行符) {
                ++开始;
            }
            contents ~= "\n"d;
            start = .开始;
            continue;
        }
        ++开始;
    }
    .tokenValue = contents;
    return .tokenValue;
}
